package com.itcoon.cloud.framework.security.handler;

import com.itcoon.cloud.framework.security.event.UserLoginSuccessEvent;
import com.itcoon.cloud.framework.security.model.UserPrincipal;
import com.itcoon.cloud.framework.security.model.AuthToken;
import com.itcoon.cloud.framework.security.utils.AuthTokenUtil;
import com.itcoon.cloud.framework.security.utils.JwtTokenUtil;
import com.itcoon.cloud.framework.webmvc.response.ApiResponse;
import com.itcoon.cloud.framework.webmvc.utils.ApiResponseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class JwtAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private static final Logger log = LoggerFactory.getLogger(JwtAuthenticationSuccessHandler.class);

    private final ApplicationEventPublisher eventPublisher;


    public JwtAuthenticationSuccessHandler(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        Object principal = authentication.getPrincipal();
        try {
            if (principal instanceof UserPrincipal) {
                UserPrincipal userPrincipal = (UserPrincipal) principal;
                log.info("{} login success!", userPrincipal.getUsername());
                eventPublisher.publishEvent(new UserLoginSuccessEvent(userPrincipal));
                String accessToken = JwtTokenUtil.generateAccessToken(userPrincipal);
                String refreshToken = JwtTokenUtil.generateRefreshToken(userPrincipal.getUsername());
                Date accessExpiration = JwtTokenUtil.getExpirationFromToken(accessToken);
                Date refreshExpiration = JwtTokenUtil.getExpirationFromToken(refreshToken);
                AuthToken authToken = new AuthToken(accessToken, refreshToken,
                        LocalDateTime.ofInstant(accessExpiration.toInstant(), ZoneId.systemDefault()),
                        LocalDateTime.ofInstant(refreshExpiration.toInstant(), ZoneId.systemDefault()), userPrincipal.getId());
                AuthTokenUtil.saveToken(userPrincipal.getId(), authToken);
                eventPublisher.publishEvent(userPrincipal);
                ApiResponseUtils.writeJsonResponse(response, ApiResponse.ok(authToken), HttpServletResponse.SC_OK);
                return;
            }
            ApiResponseUtils.writeJsonResponse(response, ApiResponse.ok(principal), HttpServletResponse.SC_OK);
        }catch (Exception e){
            log.error(e.getMessage(), e);
            ApiResponseUtils.writeJsonResponse(response, ApiResponse.error(), HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }
}
